package com.cms.common.model.services.impl;

import com.cms.common.aop.permission.PermissionCheck;
import com.cms.common.context.ApplicationContextProvider;
import com.cms.common.exception.SystemException;
import com.cms.common.exception.ViewTypeEnum;
import com.cms.common.model.criteria.Criteria;
import com.cms.common.model.criteria.Restrictions;
import com.cms.common.model.entity.AdminUser;
import com.cms.common.model.entity.Permission;
import com.cms.common.model.entity.Roles;
import com.cms.common.model.repository.PermissionRepository;
import com.cms.common.model.services.PermissionService;
import com.cms.common.model.vo.PermissionVo;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;


@Service
@Slf4j
public class PermissionServiceImpl implements PermissionService {


    public void initPermission() {
        //主程序的权限扫描
        Criteria<Permission> systemPermissionCriteria = new Criteria();
        systemPermissionCriteria.add(Restrictions.isNull("pluginId"));
        PermissionRepository permissionRepository = ApplicationContextProvider.getBean(PermissionRepository.class);
        List<Permission> permissions = permissionRepository.findAll(systemPermissionCriteria);
        Map<String, Permission> oldPermissionsMap = new HashMap<>();
        if (permissions != null && permissions.size() > 0) {
            for (Permission permission : permissions) {
                oldPermissionsMap.put(permission.getRoute(), permission);
            }
        }
        List<String> allPermissions = new ArrayList<>();
        Map<String, Permission> routePermissionsMap = new HashMap<>();
        Reflections f = new Reflections("com.cms.controllers");
        Set<Class<?>> clazzes = f.getTypesAnnotatedWith(RequestMapping.class);//获取所有接口类
        Iterator<Class<?>> it = clazzes.iterator();
        while (it.hasNext()) {
            Class<?> clazz = it.next();
            initPermissions(clazz, allPermissions, oldPermissionsMap, routePermissionsMap);
        }

        //清除过期数据
        systemPermissionCriteria.add(Restrictions.notIn("route", allPermissions));
        systemPermissionCriteria.add(Restrictions.isNull("pluginId"));
        List<Permission> systemPermissions1 = permissionRepository.findAll(systemPermissionCriteria);
        if (systemPermissions1 != null && systemPermissions1.size() > 0) {
            permissionRepository.deleteAll(systemPermissions1);
        }

    }

    private void initPermissions(Class<?> clazz, List<String> allPermissions, Map<String, Permission> oldPermissionsMap, Map<String, Permission> routePermissionsMap) {
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(clazz, RequestMapping.class);//获取restcontroller上的地址
        if (requestMapping == null) {
            return;
        }
        String[] classUris = requestMapping.value();
        String classUri = classUris[0];

        Method[] ms = clazz.getMethods();
        for (Method method : ms) {
            PermissionCheck permissionAnnotation = AnnotationUtils.findAnnotation(method, PermissionCheck.class);//获取method上的
            if (permissionAnnotation == null) {
                continue;
            }

            Annotation[] declaredAnnotations = method.getDeclaredAnnotations();

            String route = null;
            String methodUri = "";
            RequestMethod[] methods1 = null;
            StringBuffer stringBuffer = new StringBuffer();
            if (hasRequestMappingAnnotation(method)) {
                RequestMapping requestMappingAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);//获取method上的
                if (requestMappingAnnotation != null) {
                    String[] methodUris = requestMappingAnnotation.value();
                    methodUri = methodUris.length == 0 ? "" : methodUris[0];
                    methods1 = requestMappingAnnotation.method();
                    if (methods1 != null) {
                        for (RequestMethod m : methods1) {
                            stringBuffer.append(m + "#");
                        }
                    }
                }
            } else if (hasGetMappingAnnotation(method)) {
                GetMapping requestMappingAnnotation = AnnotationUtils.findAnnotation(method, GetMapping.class);//获取method上的
                if (requestMappingAnnotation != null) {
                    String[] methodUris = requestMappingAnnotation.value();
                    methodUri = methodUris.length == 0 ? "" : methodUris[0];
                    stringBuffer.append("get#");
                }
            } else if (hasPostMappingAnnotation(method)) {
                PostMapping requestMappingAnnotation = AnnotationUtils.findAnnotation(method, PostMapping.class);//获取method上的
                if (requestMappingAnnotation != null) {
                    String[] methodUris = requestMappingAnnotation.value();
                    methodUri = methodUris.length == 0 ? "" : methodUris[0];
                    stringBuffer.append("post#");
                }
            } else if (hasPutMappingAnnotation(method)) {
                PutMapping requestMappingAnnotation = AnnotationUtils.findAnnotation(method, PutMapping.class);//获取method上的
                if (requestMappingAnnotation != null) {
                    String[] methodUris = requestMappingAnnotation.value();
                    methodUri = methodUris.length == 0 ? "" : methodUris[0];
                    stringBuffer.append("put#");
                }
            } else if (hasDeleteMappingAnnotation(method)) {
                DeleteMapping requestMappingAnnotation = AnnotationUtils.findAnnotation(method, DeleteMapping.class);//获取method上的
                if (requestMappingAnnotation != null) {
                    String[] methodUris = requestMappingAnnotation.value();
                    methodUri = methodUris.length == 0 ? "" : methodUris[0];
                    stringBuffer.append("delete#");
                }
            }


            route = classUri + methodUri + "@" + stringBuffer.toString().toLowerCase();

            Permission permission = null;
            if (oldPermissionsMap.containsKey(route)) {//存在
                permission = oldPermissionsMap.get(route);
            } else {
                permission = new Permission();
                permission.setRoute(route);
            }
            permission.setName(permissionAnnotation.name());
            permission.setTypeName(permissionAnnotation.typeName());
            PermissionRepository permissionRepository = ApplicationContextProvider.getBean(PermissionRepository.class);
            permissionRepository.saveAndFlush(permission);
            allPermissions.add(route);
            routePermissionsMap.put(permission.getRoute(), permission);
        }
    }

    private boolean hasRequestMappingAnnotation(Method method) {
        return method.isAnnotationPresent(RequestMapping.class);
    }

    private boolean hasGetMappingAnnotation(Method method) {
        return method.isAnnotationPresent(GetMapping.class);
    }

    private boolean hasPostMappingAnnotation(Method method) {
        return method.isAnnotationPresent(PostMapping.class);
    }

    private boolean hasPutMappingAnnotation(Method method) {
        return method.isAnnotationPresent(PutMapping.class);
    }

    private boolean hasDeleteMappingAnnotation(Method method) {
        return method.isAnnotationPresent(DeleteMapping.class);
    }

    public boolean checkPermission(Method targetMethod, Class<?> clazz) throws Exception {
        log.info("====================开始检测权限============================");
        //获取方法上注解中表明的权限
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        AdminUser adminUser = (AdminUser) request.getAttribute("adminUser");
        if (adminUser != null && adminUser.getId() == 1) {//初始化超管
            return true;
        }
        PermissionCheck actionLogTaget = AnnotationUtils.findAnnotation(targetMethod, PermissionCheck.class);
        if (actionLogTaget == null) {//未检测到权限校验的注解
            return true;
        }

        RequestMapping controllerMapping = AnnotationUtils.findAnnotation(clazz, RequestMapping.class);//类上的
        String[] classUris = controllerMapping.value();

        RequestMapping methodMapping = AnnotationUtils.findAnnotation(targetMethod, RequestMapping.class);//方法上的
        String[] methodUris = methodMapping.value();
        RequestMethod[] methods = methodMapping.method();

        StringBuffer stringBuffer = new StringBuffer();
        for (RequestMethod m : methods) {
            stringBuffer.append(m + "#");
        }

        String methodUri = methodUris.length == 0 ? "" : methodUris[0];
        String route = classUris[0] + methodUri + "@" + stringBuffer.toString().toLowerCase();


        ResponseBody responseBody = AnnotationUtils.findAnnotation(targetMethod, ResponseBody.class);//方法上的
        int viewType = ViewTypeEnum.API_ADMIN.getIndex();
        if (responseBody == null) {
            viewType = ViewTypeEnum.WEB_ADMIN.getIndex();
        }

        return checkPermission(adminUser, route, viewType);

    }

    @Override
    public boolean checkPermission(AdminUser adminUser, String route, int type) {
        if (adminUser == null) {
            SystemException.throwException(type, "权限不足");
        }
        Roles role = adminUser.getRoles();
        if (role == null) {
            SystemException.throwException(type, "权限不足");
        }
        List<Permission> permissionList = role.getPermissions();
        if (permissionList == null || permissionList.size() == 0) {
            SystemException.throwException(type, "权限不足");
        }
        for (Permission permission1 : permissionList) {
            if (permission1.getRoute().equals(route)) {//有该权限，继续执行被切方法
                log.info("====================权限检测成功============================");
                return true;
            }
        }
        SystemException.throwException(type, "权限不足");
        return false;
    }

    @Override
    public List<Permission> getAllPermissions() {
        PermissionRepository permissionRepository = ApplicationContextProvider.getBean(PermissionRepository.class);
        List<Permission> permissionList = permissionRepository.findAll();
        return permissionList;
    }

    @Override
    public List<Permission> getPermissionsByIds(List<Long> ids) {
        PermissionRepository permissionRepository = ApplicationContextProvider.getBean(PermissionRepository.class);
        return permissionRepository.findAllByIdIn(ids);
    }

    @Override
    public List<PermissionVo> getAllPermissionVos(boolean isPlugin) {
        PermissionRepository permissionRepository = ApplicationContextProvider.getBean(PermissionRepository.class);

        List<Permission> permissionList = null;
        if (isPlugin) {
            permissionList = permissionRepository.findAllByPluginIdIsNotNull();
        } else {
            permissionList = permissionRepository.findAllByPluginIdIsNull();
        }
        Map<String, List<Permission>> permissionsByType = new HashMap<>();
        for (Permission permission : permissionList) {
            String typeName = permission.getTypeName();
            if (!permissionsByType.containsKey(typeName)) {
                permissionsByType.put(typeName, new ArrayList<Permission>());
            }
            permissionsByType.get(typeName).add(permission);
        }
        List<PermissionVo> permissionVoList = new ArrayList<>();
        for (Map.Entry<String, List<Permission>> entry : permissionsByType.entrySet()) {
            PermissionVo permissionVo = new PermissionVo();
            // Assuming PermissionVo has appropriate setters for Permission fields
            permissionVo.setTypeName(entry.getKey());
            permissionVo.getPermissionList().addAll(entry.getValue());
            // Set other fields as necessary
            permissionVoList.add(permissionVo);
        }
        return permissionVoList;
    }

    @Override
    public List<PermissionVo> getAllPermissionVos(boolean isPlugin, List<Permission> checkedPermissions) {
        List<Long> pIds = new ArrayList<>();
        for (Permission permission : checkedPermissions) {
            pIds.add(permission.getId());
        }
        List<PermissionVo> permissionVos = getAllPermissionVos(isPlugin);
        for (PermissionVo permissionVo : permissionVos) {
            if (permissionVo.getPermissionList() != null) {
                for (Permission permission : permissionVo.getPermissionList()) {
                    if (pIds.contains(permission.getId())) {
                        permission.setChecked(true);
                    }
                }
            }
        }
        return permissionVos;
    }

}
